use std::error::Error;
use std::fs;
use std::sync::{Arc, Mutex};
use std::time::SystemTime;
use syntect::easy::HighlightLines;
use syntect::highlighting::ThemeSet;
use syntect::parsing::SyntaxSet;
use syntect::util::LinesWithEndings;
use egui;
use once_cell::sync::Lazy;

static SYNTAX_SET: Lazy<SyntaxSet> = Lazy::new(SyntaxSet::load_defaults_newlines);
static THEME_SET: Lazy<ThemeSet> = Lazy::new(ThemeSet::load_defaults);

pub fn save_json_to_file(latest_json: &Arc<Mutex<Option<String>>>) -> Result<String, Box<dyn Error>> {
    let latest = latest_json.lock().map_err(|_| "Failed to lock latest_json")?;
    if let Some(json) = latest.as_ref() {
        // Create output directory if it doesn't exist
        fs::create_dir_all("output")?;
        
        let timestamp = SystemTime::now()
            .duration_since(SystemTime::UNIX_EPOCH)?
            .as_secs();
        let filename = format!("output/mqtt_message_{}.json", timestamp);
        fs::write(&filename, json)?;
        Ok(filename)
    } else {
        Err("No JSON message to save".into())
    }
}

pub fn highlight_json(json_str: &str, ui: &mut egui::Ui) {
    let syntax = SYNTAX_SET
        .find_syntax_by_extension("json")
        .unwrap_or_else(|| SYNTAX_SET.find_syntax_plain_text());
    let theme = THEME_SET
        .themes
        .get("base16-ocean.dark")
        .unwrap_or_else(|| THEME_SET.themes.values().next().expect("ThemeSet is empty"));
    let mut h = HighlightLines::new(syntax, theme);
    
    let mut layout_job = egui::text::LayoutJob::default();
    for line in LinesWithEndings::from(json_str) {
        let ranges: Vec<(syntect::highlighting::Style, &str)> =
            h.highlight_line(line, &SYNTAX_SET).unwrap();
        for (style, text) in ranges {
            let color = style.foreground;
            let color = egui::Color32::from_rgb(color.r, color.g, color.b);
            let format = egui::text::TextFormat {
                color,
                font_id: egui::FontId::monospace(12.0),
                ..Default::default()
            };
            layout_job.append(text, 0.0, format);
        }
    }
    ui.label(layout_job);
}

pub fn setup_custom_fonts(ctx: &egui::Context) {
    let mut fonts = egui::FontDefinitions::default();
    
    fonts.font_data.insert(
        "noto_sans_sc".to_owned(),
        egui::FontData::from_static(include_bytes!("../assets/NotoSansSC-Regular.ttf"))
    );
    
    fonts.families
        .entry(egui::FontFamily::Proportional)
        .or_default()
        .insert(0, "noto_sans_sc".to_owned());
    
    fonts.families
        .entry(egui::FontFamily::Monospace)
        .or_default()
        .push("noto_sans_sc".to_owned());
    
    ctx.set_fonts(fonts);
} 
